Creating and Drawing Paths
Like a polygon contour, a path contour is a series of connected points. However, whereas a polygon contour is made up of straight lines, a path contour can contain both straight lines and curves. Therefore, the geometric points that make up a path contour can be on-curve points or off-curve control points. QuickDraw GX defines thegxPath
structure to encapsulate a path contour geometry:
struct gxPath { long vectors; long controlBits[gxAnyNumber]; struct gxPoint vector[gxAnyNumber]; };Thevectors
field indicates the number of geometric points in the path and thevector
array contains the geometric points themselves. ThecontrolBits
array specifies which geometric points are on-curve points and which are off-curve control points. A value of 0 indicates an on-curve point and a value of 1 indicates an off-curve point. For example, acontrolBits
field with the value
0x55555555 /* 0101 0101 0101 0101 ... */indicates that every other point is an off-curve control point; the first point is on curve, the second point is off, and so on. As another example, acontrolBits
field value of
0x00000000 /* 0000 0000 0000 0000 ... */indicates all points are on curve, which effectively creates a polygon.Notice that the
controlBits
array allows you to specify sequential off-curve control points. For example, acontrolBits
value of
0xFFFFFFFF /* 1111 1111 1111 1111 ... */indicates that all points are off curve. When you indicate that two control points in a row are off curve, QuickDraw GX assumes an on-curve point midway between them. (The example in Listing 2-17 on page 2-59 gives an example.)Like the polygon shape, the path shape allows you to group any number of contours within a single QuickDraw GX shape. The
gxPaths
structure encapsulates the multiple-path geometry:
struct gxPaths { long contours; struct gxPath contour[gxAnyNumber]; };Thecontours
field indicates the total number of contours (in other words, the total number of separate paths), and thecontour
array contains the path geometries.Creating Paths With a Single Contour
Since agxPaths
structure is of variable length and every element in it is of typelong
, you can define a path geometry as an array of long values. The sample function in Listing 2-16 shows how to define a path geometry as an array of long values, and then draw a path shape using theGXDrawPaths
function. Since theGXDrawPaths
function expects its first parameter to be a pointer to agxPaths
structure, the sample function casts the array of long values to the appropriate type using the expression
(gxPaths *) aPathGeometrybefore sending the information to theGXDrawPaths
function.Listing 2-16 Drawing a path shape
void DrawAPathShape(void) { static long aPathGeometry[] = {1, /* number of contours */ 6, /* number of points */ 0x48000000, /* 0100 1000 */ ff(50), ff(100), /* on */ ff(0), ff(75), /* off */ ff(50), ff(50), /* on */ ff(150), ff(50), /* on */ ff(200), ff(75), /* off */ ff(150), ff(100)}; /* on */ GXDrawPaths((gxPaths *) aPathGeometry, gxOpenFrameFill); }The path defined in this example has four on-curve points and two off-curve points. When drawn with the open-frame shape fill, it contains two curves and one straight line, as shown in Figure 2-33.
The sample function from Listing 2-16 draws the path without creating a path shape. It could instead create a path shape with the
GXNewPaths
function:
aPathsShape = GXNewPaths((gxPaths *) aPathGeometry);and then draw it using theGXDrawShape
function:
GXDrawShape(aPathsShape);You can also create path shapes using theGXNewShape
function:
aPathsShape = GXNewShape(gxPathType); GXSetPaths(aPathsShape, (gxPaths *) aPathGeometry);or by using theGXNewShapeVector
function:
aPathsShape = GXNewShapeVector(gxPathType, aPathGeometry);Notice that in this case you do not have to cast the aPathGeometry array to be a pointer to agxPaths
structure. TheGXNewShapeVector
function expects an array of long values.Although the
GXDrawPaths
function (shown in Listing 2-16) allows you to specify a shape fill, theGXDrawShape
function does not. If you create a path shape and you want it to have a different shape fill than the default path shape, you must indicate the desired shape fill using theGXSetShapeFill
function--for example,
GXSetShapeFill(aPathsShape, gxInverseEvenOddFill);For more information about shape fills, see "Shape Fill" beginning on page 2-12.Creating Paths Using Only Off-Curve Points
The sample function in Listing 2-17 shows how you can create a path using only off-curve control points. The path defined in this example contains four control points, and thecontrolBits
field is set to
0xF0000000 /* 1111 0000 0000 0000 0000 ... */which indicates that the first four points are off curve. The path contains only four points, and therefore they are all off curve.Listing 2-17 Creating a path using only off-curve control points
void CreateRoundPath(void) { gxShape aPathShape; static long aPathGeometry[] = {1, /* number of contours */ 4, /* number of points */ 0xF0000000, /* 1111 0000 ... */ ff(50), ff(50), /* off */ ff(150), ff(50), /* off */ ff(150), ff(150), /* off */ ff(50), ff(150)}; /* off */ aPathShape = GXNewPaths((gxPaths *) aPathGeometry); GXDrawShape(aPathShape); }The four off-curve control points in this example form a square; the path that they define is a rounded square, as shown in Figure 2-34.Figure 2-34 A round path shape
Notice that the path is filled with the even-odd shape fill, which is the default for path shapes. You could, however, specify any shape fill for this path except the open-frame shape fill. The open-frame shape fill requires that the first and last points of the contour be on-curve points, and this path has no on-curve points.
Creating Paths With Multiple Contours
The sample function in Listing 2-18 shows how a single path shape can contain more than one path contour. The path shape defined in this example includes the round path from the previous example as well as a second round path, entirely contained within the first.Listing 2-18 Creating a path with concentric contours
void CreateHollowCircles(void) { gxShape aPathShape; static long aPathGeometry[] = {2, /* number of contours */ 4, /* number of points */ 0xF0000000, /* 1111 0000 ... */ ff(50), ff(50), /* off */ ff(150), ff(50), /* off */ ff(150), ff(150), /* off */ ff(50), ff(150), /* off */ 4, /* number of points */ 0xF0000000, /* 1111 0000 ... */ ff(65), ff(65), /* off */ ff(135), ff(65), /* off */ ff(135), ff(135), /* off */ ff(65), ff(135)}; /* off */ aPathShape = GXNewPaths((gxPaths *) aPathGeometry); GXSetShapeFill(aPathShape, gxClosedFrameFill); GXDrawShape(aPathShape); GXDisposeShape(aPathShape); }The result of this function is shown in Figure 2-35.Figure 2-35 A path shape with two concentric clockwise contours and closed-frame shape fill
You can change the shape fill of this polygon by removing this line of code from the sample function in Listing 2-18:
GXSetShapeFill(aPolygonsShape, gxClosedFrameFill);If you don't specify a shape fill, theGXNewPaths
function uses the shape fill from the default path shape, which is the even-odd shape fill (unless you change it using theGXGetDefaultShape
andGXSetShapeFill
functions). The path shape resulting from an even-odd shape fill is shown in Figure 2-36.Figure 2-36 A path shape with two concentric clockwise contours and even-odd shape fill
Notice that the even-odd shape fill causes QuickDraw GX to fill in the outer contour, but not the inner contour. However, if you specify the winding shape fill for this path using the call
GXSetShapeFill(aPathShape, gxWindingFill);the resulting shape would appear as shown in Figure 2-37.Figure 2-37 A path shape with two concentric clockwise contours and winding shape fill
Unlike the even-odd shape fill, the winding shape fill causes QuickDraw GX to fill inner contours--as long as the inner contour has the same contour direction as the outer contour. If the inner contour and the outer contour have opposite contour directions, neither the even-odd shape fill nor the winding shape fill will fill the inner contour.
For example, if you change the direction of the inner contour from the previous example by reversing the order of the second path's geometric points, as in the declaration
static long aPathGeometry[] = {2, /* number of contours */ 4, /* number of points */ 0xF0000000, /* 1111 0000 */ ff(50), ff(50), /* off */ ff(150), ff(50), /* off */ ff(150), ff(150), /* off */ ff(50), ff(150), /* off */ 4, /* number of points */ 0xF0000000, /* 1111 0000 */ ff(65), ff(135), /* off */ ff(135), ff(135), /* off */ ff(135), ff(65), /* off */ ff(65), ff(65)}; /* off */and set the shape fill to the closed-frame shape fill using the call
GXSetShapeFill(aPathShape, gxClosedFrameFill);the resulting shape has contours with opposite contour directions, as depicted in
Figure 2-38.Figure 2-38 A path shape with an internal counterclockwise contour and closed-frame shape fill
Since the outer contour and the inner contour have opposite contour directions, neither the even-odd shape fill nor the winding shape fill cause QuickDraw GX to fill the inner contour, as shown in Figure 2-39.
Figure 2-39 A path shape with even-odd or winding shape fill
For more information about contour direction and shape-filling algorithms, see "Shape Fill" on page 2-12.
For more information about path shapes, see "Path Shapes" on page 2-25 and "Path Structures" on page 2-107.
For information about the functions you can use to create and draw paths, see the description of the
GXNewPaths
function on page 2-117 and theGXDrawPaths
function on page 2-162.
Main | Page One | What's New | Apple Computer, Inc. | Find It | Contact Us | Help